package com.zhouchao.persistence.session;

import com.mysql.jdbc.StringUtils;
import com.zhouchao.persistence.config.BoundSql;
import com.zhouchao.persistence.pojo.Configuration;
import com.zhouchao.persistence.pojo.MappedStatement;
import com.zhouchao.persistence.utils.GenericTokenParser;
import com.zhouchao.persistence.utils.ParameterMapping;
import com.zhouchao.persistence.utils.ParameterMappingTokenHandler;

import java.beans.PropertyDescriptor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.sql.*;
import java.util.ArrayList;
import java.util.List;

/**
 * @Author: zhouchao
 * @Date: 2021/05/03 21:18
 * @Description:
 */
public class SimpleExecutor implements Executor {
    @Override
    public <T> List<T> query(Configuration configuration, MappedStatement mapperStatement, Object... params) throws Exception {
        Connection connection = configuration.getDataSource().getConnection();

        // 此时的sql是带有占位符的，需要把“#{XXX}”转换成?,并赋值
        String sql = mapperStatement.getSql();

        BoundSql boundSql = getBoundSql(sql);

        // 获取预处理对象：PreparedStatement
        PreparedStatement preparedStatement = connection.prepareStatement(boundSql.getSql());

        // 设置参数
        String parameterType = mapperStatement.getParameterType();
        Class<?> parameterTypeClass = getClassType(parameterType);
        List<ParameterMapping> parameterMappings = boundSql.getParameterMappings();
        for (int i = 0; i < parameterMappings.size(); i++) {
            ParameterMapping parameterMapping = parameterMappings.get(i);
            String content = parameterMapping.getContent();
            Field field = parameterTypeClass.getDeclaredField(content);
            field.setAccessible(true);
            Object o = field.get(params[0]);
            preparedStatement.setObject(i + 1, o);
        }

        // 执行 sql
        ResultSet resultSet = preparedStatement.executeQuery();

        // 封装返回结果集
        String resultType = mapperStatement.getResultType();
        Class<?> resultTypeClass = getClassType(resultType);
        List<T> resultList = new ArrayList<>();

        while (resultSet.next()) {
            Object result = resultTypeClass.newInstance();
            ResultSetMetaData resultSetMetaData = resultSet.getMetaData();
            for (int i = 1; i <= resultSetMetaData.getColumnCount(); i++) {
                String columnName = resultSetMetaData.getColumnName(i);
                Object value = resultSet.getObject(columnName);

                // 通过bean的自省完成封装
                PropertyDescriptor propertyDescriptor = new PropertyDescriptor(columnName, resultTypeClass);
                Method method = propertyDescriptor.getWriteMethod();
                method.invoke(result, value);
            }
            resultList.add((T) result);
        }

        return resultList;
    }

    @Override
    public int update(Configuration configuration, MappedStatement mapperStatement, Object params) throws Exception {
        Connection connection = configuration.getDataSource().getConnection();

        // 此时的sql是带有占位符的，需要把“#{XXX}”转换成?,并赋值
        String sql = mapperStatement.getSql();

        BoundSql boundSql = getBoundSql(sql);

        // 获取预处理对象：PreparedStatement
        PreparedStatement preparedStatement = connection.prepareStatement(boundSql.getSql());

        // 设置参数
        String parameterType = mapperStatement.getParameterType();
        Class<?> parameterTypeClass = getClassType(parameterType);
        List<ParameterMapping> parameterMappings = boundSql.getParameterMappings();
        for (int i = 0; i < parameterMappings.size(); i++) {
            ParameterMapping parameterMapping = parameterMappings.get(i);
            String content = parameterMapping.getContent();
            Field field = parameterTypeClass.getDeclaredField(content);
            field.setAccessible(true);
            Object o = field.get(params);
            preparedStatement.setObject(i + 1, o);
        }

        return preparedStatement.executeUpdate();
    }

    private Class<?> getClassType(String clazz) throws ClassNotFoundException {
        Class<?> aClass = null;
        if (!StringUtils.isNullOrEmpty(clazz)) {
            aClass = Class.forName(clazz);
        }
        return aClass;
    }

    private BoundSql getBoundSql(String sql) {
        // 标记处理类，配置标记解析器来完成对诈伪付的解析处理工作
        ParameterMappingTokenHandler parameterMappingTokenHandler = new ParameterMappingTokenHandler();
        GenericTokenParser genericTokenParser = new GenericTokenParser("#{", "}", parameterMappingTokenHandler);

        String parseSql = genericTokenParser.parse(sql);
        List<ParameterMapping> parameterMappings = parameterMappingTokenHandler.getParameterMappings();
        BoundSql boundSql = new BoundSql(parseSql, parameterMappings);
        return boundSql;
    }
}
